#if UNITY_EDITOR || UNITY_ANDROID || UNITY_IOS

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using CSUtils; 
using UnityEngine;
namespace U3dUtils
{
    /// <summary>
    /// mono监听器
    /// </summary>
    public class CMonoMonitor : U3dSingleton<CMonoMonitor>
    {
        const string _tag = "U3dUtils.CMonoMonitor";
        public static bool isBackRun { get; private set; }
        public static bool isQuit { get; private set; }
        public static event Action onUpdateEvent;
        public static event Action onFixedUpdateEvent;
        public static event Action onLateUpdateEvent;
        static Dictionary<Action, object> _appQuit_objDic = new Dictionary<Action, object>();
        static Dictionary<Action<bool>, object> _appIsBackRunEvent_objDic = new Dictionary<Action<bool>, object>();
        static Dictionary<byte, int> eventType_frameCountDic = new Dictionary<byte, int>();
        static Dictionary<string, CEvent> eventKey_updateEventDic = new Dictionary<string, CEvent>();
        static CEvent[] _eventArr = new CEvent[0];
        static int mainThreadId = 1;
        int lastAppQuitFrameCount;
        //#if UNITY_EDITOR || UNITY_ANDROID ||UNITY_IOS

        //[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.AfterSceneLoad)]
        //#endif
        internal static void __Init()
        {
            var vv = CMonoMonitor.Instance;
        }

        public static MonoBehaviour mono { get { return Instance; } }

        public static CEvent UpdateEventAdd(string eventKey, float internalTime, object noNullObj, Action<float> onEvent)
        {
            __Init();
            if (eventKey_updateEventDic.ContainsKey(eventKey))
            {
                CLog.E(_tag, $"错误_UpdateEventAdd_已经存在.将被覆盖........{internalTime}......{eventKey}");
            }
            //CLog.i(tag, $"添加Update事件...............{internalTime}......{eventKey}.....Count={eventKey_updateEventDic.Count}");
            var _event = new CEvent(eventKey, internalTime, -1, noNullObj, onEvent);
            eventKey_updateEventDic[eventKey] = _event;

            return _event;
        }

        public static void UpdateEventRemove(string eventKey)
        {
            __Init();
            if (eventKey_updateEventDic.ContainsKey(eventKey))
            {
                eventKey_updateEventDic.Remove(eventKey);
                _instance._isDirty = true;
            } else
            {
                //CLog.E(tag, "错误_UpdateEventRemove_不存在 无法删除");
            }
        }

        /// <summary>
        /// 后台线程回调到主线程
        /// </summary> 
        public static void ToMainTherad(string eventKey, Action<float> onEvent)
        {
            ToMainTherad(eventKey, 0, onEvent);
        }

        public static void ToMainTherad(string eventKey, float internalTime, Action<float> onEvent)
        {
            __Init();

            if (eventKey_updateEventDic.ContainsKey(eventKey))
            {
                CLog.E(_tag, $"错误_UpdateEventAdd_已经存在.将被覆盖........{internalTime}......{eventKey}");
            }
            //CLog.i(tag, $"添加Update事件...............{internalTime}......{eventKey}.....Count={eventKey_updateEventDic.Count}");
            var _event = new CEvent(eventKey, internalTime, 1, "obj", onEvent);
            eventKey_updateEventDic[eventKey] = _event;
        }

        public static void RegisterAppIsBackRunEvent(object obj, Action<bool> call)
        {
            __Init();
            _appIsBackRunEvent_objDic[call] = obj;
        }

        public static void RegisterAppQuitEvent(object obj, Action call)
        {
            __Init();
            _appQuit_objDic[call] = obj;
        }

        void Awake()
        {
            _instance = this; //提前初始化单例---防止之后隐藏对象时初始化引起的错误
            Debug.Log($"{_tag}.....Awake()");
        }

        void OnEnable()
        {
            Debug.Log($"{_tag}.....OnEnable()");
            RefreshLogTime();
        }

        void OnDisable()
        {
            Debug.Log($"{_tag}.....OnDisable()");
        }

        void OnValidate()
        {
            Debug.Log($"{_tag}.....OnValidate()");
        }

        bool _isDirty;

        void _CalcDataArr()
        {
            if (_isDirty == false)
            {
                return;
            }
            _isDirty = false;
            _eventArr = eventKey_updateEventDic.Values.ToArray();
        }

        void Update()
        {
            if (_isDirty)
            {
                _CalcDataArr();
            }
            //RefreshLogTime(Time.frameCount);
            CDelayMain.IUpdate(null);
            try
            {
                onUpdateEvent?.Invoke();
            } catch (Exception ex)
            {
                CLog.Ex(_tag, "错误__", ex);
            }
            for (int i = 0; i < _eventArr.Length; i++)
            {
                var eventt = _eventArr[i];
                var diffTime = CTime.realtimeSinceStartup - eventt._lastTime;
                //CLog.i(tag, $"Update....{i}/{eventt.eventKey}......time={Time.time}.....diff={diff}/internalTime={eventt.internalTime}");
                if (diffTime > eventt.internalTime)
                {
                    eventt._lastTime = CTime.realtimeSinceStartup;
                    try
                    {
                        eventt._currLoopCount++;
                        if (eventt.noNullObj == null || eventt.noNullObj.Equals(null))
                        {
                            eventKey_updateEventDic.Remove(eventt.eventKey);
                        } else if (eventt.loopTotalCount < 0 || eventt.loopTotalCount > eventt._currLoopCount)
                        {
                            eventt.onEvent?.Invoke(diffTime);
                        } else
                        {
                            eventKey_updateEventDic.Remove(eventt.eventKey);
                            eventt.onEvent?.Invoke(diffTime);
                        }
                    } catch (Exception ex)
                    {
                        CLog.Ex(_tag, "错误___", ex);
                    }
                }
            }
            if (_eventArr.Length != eventKey_updateEventDic.Count)
            {
                _eventArr = eventKey_updateEventDic.Values.ToArray();
            }
        }

        public class CEvent
        {
            public string eventKey;
            public float internalTime;
            internal float _lastTime;
            public object noNullObj;
            public Action<float> onEvent;
            public int _currLoopCount;
            public int loopTotalCount;

            public CEvent(string eventKey, float internalTime, int loopTotalCount, object noNullObj, Action<float> onEvent)
            {
                this.eventKey = eventKey;
                this.internalTime = internalTime;
                this.loopTotalCount = loopTotalCount;
                this.noNullObj = noNullObj;
                this.onEvent = onEvent;
                _lastTime = CTime.realtimeSinceStartup;
            }

            public override string ToString() => eventKey;
        }

        public static void RefreshLogTime()
        {
            if (CTime.frameCount == Time.frameCount)
            {
                return;
            }
            if (mainThreadId != Thread.CurrentThread.ManagedThreadId)
            {
                return;
            }
            //return;

            CTime.SetData(Time.frameCount, Time.time, Time.timeScale, Time.deltaTime, Time.realtimeSinceStartup, Time.realtimeSinceStartup + "_" + Time.frameCount);
            //Debug.Log($"{_tag}...RefreshLogTime().......timeScale={CTime.timeScale}....{CTime.currTimeStr}.....{CTime.deltaTime2}.");
        }

        void FixedUpdate()
        {
            RefreshLogTime();
            try
            {
                onFixedUpdateEvent?.Invoke();
            } catch (Exception ex)
            {
                CLog.Ex(_tag, "错误__", ex);
            }
        }

        void LateUpdate()
        {
            try
            {
                onLateUpdateEvent?.Invoke();
            } catch (Exception ex)
            {
                CLog.Ex(_tag, "错误__", ex);
            }
        }

        #region------App开启和关闭事件---------------------
        void OnApplicationPause(bool pause)
        {
            RefreshLogTime();
            CLog.i(_tag, $"OnApplicationPause(bool hasFocus) _____________是否暂停={pause}");
            _AppIsBackRun(pause, 1);
        }

        void OnApplicationFocus(bool focus)
        {
            RefreshLogTime();
            var _isBackRun = !focus;
            CLog.i(_tag, $"OnApplicationFocus(bool focus) ___________app切换到.<{(isBackRun ? "后台运行" : "前台运行")}>");
            _AppIsBackRun(_isBackRun, 2);
        }

        void _AppIsBackRun(bool _isBackRun, byte eventType)
        {
            if (eventType_frameCountDic.ContainsKey(eventType))
            {
                if (eventType_frameCountDic[eventType] < CTime.realtimeSinceStartup - 1)
                {
                    //  return;
                }
            }
            eventType_frameCountDic[eventType] = CTime.frameCount;

            if (isBackRun == _isBackRun)
            {
                CLog.i(_tag, $"_AppIsBackRun(bool _isBackRun) ___________不需要重复执行....._isBackRun={_isBackRun}");
                return;
            }
            isBackRun = _isBackRun;
            //CLog.i(tag, $"_AppIsBackRun(bool _isBackRun) ___________执行回调事件....._isBackRun={_isBackRun}");
            SendIsBackRunEvent(_isBackRun);
        }

        static void SendIsBackRunEvent(bool _isBackRun)
        {
            var removeList = new List<Action<bool>>();
            foreach (var kv in _appIsBackRunEvent_objDic)
            {
                if (kv.Value == null || kv.Value.Equals(null))
                {
                    removeList.Add(kv.Key);
                } else
                {
                    try
                    {
                        kv.Key.Invoke(_isBackRun);
                    } catch (Exception ex)
                    {
                        CLog.Ex(_tag, "错误__", ex);
                    }
                }
            }
            for (int i = 0; i < removeList.Count; i++)
            {
                _appIsBackRunEvent_objDic.Remove(removeList[i]);
            }
        }

        void OnApplicationQuit()
        {
            RefreshLogTime();
            CLog.i(_tag, "----OnApplicationQuit()----app退出---");
            #if UNITY_EDITOR
            //CLog.i(tag, "----OnApplicationQuit()----编辑器模式下对OnApplicationFocus(bool hasFocus)的修正---");
            _AppIsBackRun(true, 3);
            #else
            _AppQuit();
            #endif
        }

        void OnDestroy()
        {
            CLog.i(_tag, "----OnDestroy()----app退出---");
            _AppQuit();
        }

        void _AppQuit()
        {
            isQuit = true;
            if (lastAppQuitFrameCount == CTime.frameCount)
            {
                CLog.i(_tag, $"_AppQuit() __跳过执行_______{lastAppQuitFrameCount}/{CTime.frameCount}");
                return;
            }
            lastAppQuitFrameCount = CTime.frameCount;
            CLog.i(_tag, $"_AppQuit()....1___________执行回调事件");
            _instance = null;

            var removeList = new List<Action>();
            foreach (var kv in _appQuit_objDic)
            {
                if (kv.Value == null || kv.Value.Equals(null))
                {
                    removeList.Add(kv.Key);
                } else
                {
                    try
                    {
                        kv.Key.Invoke();
                    } catch (Exception ex)
                    {
                        CLog.Ex(_tag, "错误__", ex);
                    }
                }
            }
            for (int i = 0; i < removeList.Count; i++)
            {
                _appQuit_objDic.Remove(removeList[i]);
            }
            CDelayBg.AppEnd();
            //CDelayBg2.AppEnd();
            //CDelayBg3.AppEnd();
            CBgUpdate.AppEnd();
            CLog.i(_tag, $"_AppQuit()....2___________执行回调事件");
        }
        #endregion--------------------------
    }
}

#endif
